#ifdef CHANGED

#include "copyright.h"
#include "system.h"
#include "synchconsole.h"
#include "synch.h"

static Semaphore *readAvail;
static Semaphore *writeDone;
static Semaphore *mutex;
static Semaphore *string_mutex;
static Semaphore *int_mutex;

static void ReadAvail(void *arg) { (void) arg; readAvail->V(); }
static void WriteDone(void *arg) { (void) arg; writeDone->V(); }
static void Mutex(void *arg)     { (void) arg; mutex->V(); }

SynchConsole::SynchConsole(const char *in, const char *out) {
  readAvail = new Semaphore("read avail", 0);
  writeDone = new Semaphore("write done", 0);
  mutex = new Semaphore("mutex", 1);
  string_mutex = new Semaphore("string_mutex", 1);
  int_mutex = new Semaphore("int_mutex", 1);
  console = new Console(in, out, ReadAvail, WriteDone, 0);
}

SynchConsole::~SynchConsole() {
  delete console;
  delete writeDone;
  delete readAvail;
  delete mutex;
  delete string_mutex;
  delete int_mutex;
}

void SynchConsole::SynchPutChar(int ch) {
  mutex-> P();
  console->PutChar(ch);
  writeDone->P();
  mutex-> V();
}

int SynchConsole::SynchGetChar() {
  mutex-> P();
  readAvail->P();
  int ch = console-> GetChar();
  mutex-> V();
  return ch;
}

void SynchConsole::SynchPutString(const char s[]) {
  string_mutex-> P();
  int i = 0;
  char c = s[i];
  while (c != '\0') {
    console->PutChar(c);
    writeDone->P();
    c = s[++i];
  }
  string_mutex-> V();
}

void SynchConsole::SynchGetString(char *s, int n) {
  int ch, i;
  if (n > MAX_STRING_SIZE)
    n = MAX_STRING_SIZE;

  string_mutex-> P();
  for(i = 0; i < n; i++)  {
    readAvail->P();
    if ((ch = console->GetChar()) != EOF) {
      s[i] = ch;
      if (s[i] == '\n' || s[i] == '\0') {
	     break;
      }
    }
    else
      break;
  }

  if (s[i] != '\0')
    s[i+1] = '\0';
  string_mutex-> V();
}

void SynchConsole::SynchPutInt(int n) {
  int_mutex-> P();
  int size = round(log10(n)) + 2;
  char* num = (char*) malloc(sizeof(char) * size);
  snprintf(num, size, "%d", n);
  this->SynchPutString(num);
  int_mutex-> V();
}

int SynchConsole::SynchGetInt() {
  int_mutex-> P();
  char* str = (char*) malloc(sizeof(char) * MAX_STRING_SIZE);
  this->SynchGetString(str, MAX_STRING_SIZE);
  int n;
  sscanf(str, "%d", &n);
  int_mutex-> V();
  return n;
}

#endif // CHANGED
